<?php
declare (strict_types=1);

namespace app\admin\logic\promotion;

use app\admin\logic\system\Log;
use app\admin\model\promotion\Promotion as PromotionModel;
use app\common\exception\LogicException;
use app\common\helper\util\Page;
use app\common\helper\util\Tool;
use app\common\model\payment\admin\PaymentOrderItem;
use app\common\model\ProductType;
use app\course\logic\base\Course;
use think\annotation\Inject;

/**
 * Class Promotion
 *
 * @package app\admin\logic\promotion
 */
class Promotion extends PromotionModel
{
    /**
     * @Inject()
     * @var Course
     */
    protected $course;

    /**
     * @Inject()
     *
     * @var PaymentOrderItem
     */
    protected $paymentOrderItem;

    /**
     * @Inject()
     *
     * @var PromotionBargain
     */
    private $promotionBargainLogic;

    /**
     * @Inject()
     *
     * @var PromotionTuan
     */
    private $promotionTuanLogic;

    /**
     * 获取列表
     * Author: Martinsun <syh@sunyonghong.com>
     * Date: 2021/4/12
     *
     * @param int   $type
     * @param array $map
     * @return \think\Paginator
     * @throws \think\db\exception\DbException
     */
    public function getList(int $type, array $map = [])
    {
        return $this
            ->where('type', $type)
            ->where($map)
            ->with(['course_attach'])
            ->order('update_time', 'desc')
            ->paginate(Page::listRows())
            ->append(['product_type_text', 'active_status']);
    }

    /**
     * 获取状态选项值
     * Author: Martinsun <syh@sunyonghong.com>
     * Date: 2021/1/25
     *
     * @return array
     */
    public function getStatusOptions()
    {
        $options = $this->getStatusList();

        return Tool::parseToSelectOpions($options);
    }

    /**
     * 获取产品类型选项
     * Author: Martinsun <syh@sunyonghong.com>
     * Date: 2021/4/12
     *
     * @return array
     */
    public function getProductTypeOptions()
    {
        $options = $this->getProductType();
        $result  = [];
        foreach ($options as $key => $option) {
            $result[] = [
                'title' => $option,
                'value' => ProductType::getProductIdByKey($key)
            ];
        }
        return $result;
    }

    /**
     * 新建活动
     * Author: Martinsun <syh@sunyonghong.com>
     * Date: 2021/4/19
     *
     * @param string $type
     * @param array  $data
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function createPromotion(string $type, array $data)
    {
        $type                    = $this->getPromotionType($type);
        $data['product_type_id'] = $type;

        validate(\app\admin\validate\promotion\Promotion::class)->scene('create')->failException()->check($data);
        // 检验活动时间
        $this->checkPromotionTime($data);
        $course = $this->course->where('id', $data['course'])->field('course_type,price')->find();
        if (!$course) {
            throw new LogicException('活动课程未找到或已被删除');
        }
        $save = [
            'mhm_id'          => request()->mhm_id,
            'type'            => $type,
            'product_id'      => $data['course'],
            'product_type_id' => $course->course_type,
            'start_time'      => strtotime($data['time'][0]),
            'end_time'        => strtotime($data['time'][1])
        ];

        switch ($type) {
            case 1:// 限时打折
                $save['discount'] = $data['discount'];
                // 计算价格:  折扣 / 10 * 价格
                $save['price'] = round($data['discount'] / 10 * $course->price, 2);
                $title = '限时打折';
                break;
            case 2:// 秒杀
                $save['price'] = $data['price'];
                $title = '秒杀';
                break;
            case 3:// 砍价
                $title = '砍价';
            case 4:// 拼团
                $save['price']  = $data['price'];
                $save['num']    = $data['num'];
                $save['expiry'] = $data['expiry'] ?? 0.1;
                $title = '拼团';
                break;
        }

        $this->checkPromotionPrice($course->price, $save['price']);
        $result = $this->create($save);
        if (!$result) {
            throw new LogicException('活动创建失败');
        }
        Log::write('新建' . $title . '/' . $result->id, 'promotion', 'create', true);
    }

    /**
     * 获取活动类型值
     * Author: Martinsun <syh@sunyonghong.com>
     * Date: 2021/4/14
     *
     * @param string $type
     * @return int
     */
    public function getPromotionType(string $type)
    {
        $types = ['discount' => 1, 'seckill' => 2, 'bargain' => 3, 'tuan' => 4];

        return $types[$type] ?? 0;
    }

    /**
     * 获取活动信息
     * Author: Martinsun <syh@sunyonghong.com>
     * Date: 2021/4/15
     *
     * @param int $id
     * @return array|\think\Model
     */
    public function getPromotionById(int $id)
    {
        return $this->where('id', $id)->with(['course_attach'])->findOrFail();
    }

    /**
     * 更新单个字段
     * Author: Martinsun <syh@sunyonghong.com>
     * Date: 2021/4/15
     *
     * @param int    $id
     * @param string $field
     * @param        $value
     * @return array|\think\Model
     */
    public function editField(int $id, string $field, $value)
    {
        // 信息
        $promotion = $this->findOrFail($id);

        $promotion->$field = $value;

        if (!$promotion->save()) {
            throw new LogicException("更新失败");
        }
        Log::write('编辑活动/' . $id, 'promotion', 'update', true);
        // 返回值
        return $promotion;
    }

    /**
     * 删除版块
     * Author: Martinsun <syh@sunyonghong.com>
     * Date: 2021/4/15
     *
     * @param int $id
     */
    public function deletePromotion(int $id)
    {
        $promotion = $this->findOrFail($id);

        if (!$promotion->delete()) {
            throw new LogicException('删除失败');
        }
        Log::write('删除活动/' . $id, 'promotion', 'delete', true);
    }

    /**
     * 编辑活动
     * Author: Martinsun <syh@sunyonghong.com>
     * Date: 2021/4/15
     *
     * @param string $type
     * @param int    $id
     * @param        $data
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function editPromotion(string $type, int $id, $data)
    {
        $promotion               = $this->findOrFail($id);
        $type                    = $this->getPromotionType($type);
        $data['product_type_id'] = $type;

        validate(\app\admin\validate\promotion\Promotion::class)->scene('edit')->failException()->check($data);

        $course = $this->course->where('id', $data['course'])->field('course_type,price')->find();
        if (!$course) {
            throw new LogicException('活动课程未找到或已被删除');
        }
        // 检验活动时间
        $this->checkPromotionTime($data, [['id', '<>', $id]]);
        $promotion->product_id      = $data['course'];
        $promotion->product_type_id = $course->course_type;
        $promotion->start_time      = strtotime($data['time'][0]);
        $promotion->end_time        = strtotime($data['time'][1]);
        $promotion->expiry          = $data['expiry'] ?? 0.1;

        switch ($type) {
            case 1:// 限时打折
                $promotion->discount = $data['discount'];
                // 计算价格:  折扣 / 10 * 价格
                $promotion->price = round($data['discount'] / 10 * $course->price, 2);
                break;
            case 2:// 秒杀
                $promotion->price = $data['price'];
                break;
            case 3:// 砍价
            case 4:// 拼团
                $promotion->price = $data['price'];
                $promotion->num   = $data['num'];
                break;
        }
        $this->checkPromotionPrice($course->price, $promotion->price);
        if (!$promotion->save()) {
            throw new LogicException('活动修改失败');
        }
        Log::write('编辑活动/' . $id, 'promotion', 'update', true);
    }

    /**
     * 检验活动时间
     * Author: Martinsun <syh@sunyonghong.com>
     * Date: 2021/4/19
     *
     * @param array $data
     * @param array $where
     */
    private function checkPromotionTime(array $data, array $where = [])
    {
        $time      = $data['time'];
        $startTime = strtotime($time[0]) + 1;
        $endTime   = strtotime($time[1]) - 1;
        $id        = $this
            // ->where('product_type_id', $data['product_type_id'])
            ->where('product_id', $data['course'])
            ->where(function ($query) use ($startTime, $endTime) {
                $query->whereOr([
                    [
                        ['start_time', '<=', $startTime],
                        ['end_time', '>=', $endTime]
                    ],
                    [
                        ['start_time', '>=', $startTime],
                        ['start_time', '<=', $endTime]
                    ],
                    [
                        ['end_time', '>=', $startTime],
                        ['end_time', '<=', $endTime]
                    ]
                ]);
            })
            // ->where('start_time', '>=', $startTime)
            // ->where('end_time', '<=', $endTime)
            ->where($where)
            ->value('id');
        if ($id) {
            throw new LogicException('该课程已有同一时间段的活动');
        }
    }

    /**
     * 获取活动订单
     * Author: Martinsun <syh@sunyonghong.com>
     * Date: 2021/4/21
     *
     * @param int   $id
     * @param array $map
     * @return \think\Paginator
     * @throws \think\db\exception\DbException
     */
    public function getPromotionOrder(int $id, array $map = [])
    {
        $map[] = ['__TABLE__.promotion_id', '=', $id];
        return $this->paymentOrderItem
            ->with(['transaction', 'user', 'pdorder'])
            ->withJoin(['user', 'pdorder', 'transaction'], 'LEFT')
            ->where($map)
            ->order('update_time', 'DESC')
            ->paginate($this->getListRows());

    }

    /**
     * 获取砍价活动
     * Author: Martinsun <syh@sunyonghong.com>
     * Date: 2021/4/24
     *
     * @param int   $id
     * @param array $map
     * @return \think\Paginator
     * @throws \think\db\exception\DbException
     */
    public function getPromotionBargain(int $id, array $map = [])
    {
        $map[] = ['__TABLE__.promotion_id', '=', $id];

        return $this->promotionBargainLogic->getList($map);
    }

    /**
     * 获取拼团列表
     * Author: Martinsun <syh@sunyonghong.com>
     * Date: 2021/4/24
     *
     * @param int   $id
     * @param array $map
     * @return \think\Paginator
     * @throws \think\db\exception\DbException
     */
    public function getPromotionTuan(int $id, array $map = [])
    {
        $map[] = ['__TABLE__.promotion_id', '=', $id];

        return $this->promotionTuanLogic->getList($map);
    }

    /**
     * 检测价格
     * Author: Martinsun <syh@sunyonghong.com>
     * Date: 2021/7/6
     *
     * @param $price
     * @param $discountPrice
     */
    private function checkPromotionPrice($price, $discountPrice)
    {
        if ($discountPrice > $price) {
            throw new LogicException('活动价格不能高于销售价格');
        }

        if ($discountPrice == $price) {
            throw new LogicException('活动价格不能等于销售价格');
        }
    }

}